package org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.habilidad;

import java.util.ArrayList;

import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.Futbolista;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.futbolista.FutbolistaBase;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.Balon;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.GolAlto;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionBalon;
import org.javahispano.javacup.tacticas_aceptadas.jcrosas.chuky.util.PosicionCampo;

/**
 * @author Joan Crosas
 *
 */
public class Gol extends JugadaMortalPreparacion {
	
	public enum ExactitudGol {
		CORTO,
		LARGO
	}
	
	public enum EfectividadGol {
		GOL,
		FUERA
	}
	
	/**
	 * 
	 */
	public Gol( Futbolista futbolista ) {
		super( futbolista );
	}

	@Override
	public boolean ejecutar() {
		if( futbolista.balonEncima( futbolista.getVisionPartido().getBalon() ) && 
				futbolista.getIteracionesParaRematar() == 0 &&
				futbolista.getPosicion().distancia( FutbolistaBase.POSICION_PORTERIA_RIVAL ) < FutbolistaBase.DISTANCIA_MAX_CHUTE_PORTERIA  ) {
			
			Balon balon = evaluarGol();
			if( balon != null ) {
				if( isJugadaPosible( balon.getPosicionEnLineaFondo(), 19 ) ) {
					iniciarJugada( balon.getPosicionEnLineaFondo() );
				}
				return true;
			}
		}
		return false;
	}
	
	private Balon evaluarGol() {
		// con un 50% tengo mas que suficiente para intentarlo
		PosicionCampo posicionBalon = futbolista.getVisionPartido().getBalon().getPosicionBalon();
		
		
		double anguloPosteDer = posicionBalon.angulo( FutbolistaBase.POSICION_POSTE_DER_RIVAL );
		double anguloPosteIzq = posicionBalon.angulo( FutbolistaBase.POSICION_POSTE_IZQ_RIVAL );
		double anguloPorteria = ( anguloPosteDer + anguloPosteIzq ) / 2;
		double anguloVerticalMagico = 12.0 * Math.PI / 180;
		Balon balonMagico = new Balon( posicionBalon, anguloPorteria, futbolista.getRemate(), anguloVerticalMagico );
		if( balonMagico.getPosicionBalon( 4 ).getY() > Constantes.LARGO_CAMPO_JUEGO/2 ) {
			Comando comando = new ComandoGolpearBalon(futbolista.getIndice(), anguloPorteria*180/Math.PI, 1.0, anguloVerticalMagico*180/Math.PI );
			futbolista.getVisionPartido().addComando( comando );
			return balonMagico;
		}
		
		
		// si marcamos en el centro de la porter�a lo intentamos
		double anguloBase = posicionBalon.angulo( FutbolistaBase.POSICION_PORTERIA_RIVAL );
		double anguloError1 = anguloBase + futbolista.getPrecision() / 4; // calculamos con la mitad de error
		double anguloError2 = anguloBase - futbolista.getPrecision() / 4; 
		
		if( futbolista.getPosicion().distancia( FutbolistaBase.POSICION_PORTERIA_RIVAL ) < FutbolistaBase.DISTANCIA_MAX_CHUTE_PORTERIA / 2 ) {
			// si estem for�a aprop de la porteria mirem altres possibilitats
			if( futbolista.getPosicion().getX() < 0 ) {
				// e1 = poste_izq
				anguloError1 = posicionBalon.angulo( FutbolistaBase.POSICION_POSTE_IZQ_RIVAL );
				anguloError2 = anguloError1 - futbolista.getPrecision() / 2;
				anguloBase = anguloError2;
			} else {
				// e2 = poste_der
				anguloError2 = posicionBalon.angulo( FutbolistaBase.POSICION_POSTE_DER_RIVAL );
				anguloError1 = anguloError2 + futbolista.getPrecision() / 2;
				anguloBase = anguloError1;
				
			}
		}

		// comencem amb l'algoritme dels pases			
		ArrayList<GolAlto> goles = new ArrayList<GolAlto>();
		GolAlto golAlto;
		
		golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, 1.00, FutbolistaBase.ANGULO_VERTICAL );
		if( golAlto != null ) {
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
		}
		
		golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, 0.80, FutbolistaBase.ANGULO_VERTICAL );
		if( golAlto != null ) {
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
		}
		
		golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, 0.60, FutbolistaBase.ANGULO_VERTICAL );
		if( golAlto != null ) {
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
		}
		
		for( int j = 0; j < 14; j++) {
			GolAlto paseAltoCorto = buscarGolAlto( goles, ExactitudGol.CORTO );
			GolAlto paseAltoLargo = buscarGolAlto( goles, ExactitudGol.LARGO );
			
			double potencia = 1;
			double anguloVertical = FutbolistaBase.ANGULO_VERTICAL;
			
			if( paseAltoCorto != null && paseAltoLargo != null ) {
				potencia = (paseAltoCorto.getPotencia() + paseAltoLargo.getPotencia()) / 2;
				anguloVertical = (paseAltoCorto.getAnguloVertical() + paseAltoLargo.getAnguloVertical()) / 2;
				
				golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, potencia, anguloVertical );
				if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
					return golAlto.getBalon();
				}
				goles.add( golAlto );
				
			} else if( paseAltoCorto != null ) {
				potencia = paseAltoCorto.getPotencia();
				anguloVertical = paseAltoCorto.getAnguloVertical();
				
			} else if( paseAltoLargo != null ) {
				potencia = paseAltoLargo.getPotencia();
				anguloVertical = paseAltoLargo.getAnguloVertical();
				
			} else {
				break;
			}
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, getMitadAlta( potencia, 1.0 ), getMitadAlta( anguloVertical, FutbolistaBase.ANGULO_VERTICAL_MAX ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, potencia, getMitadAlta( anguloVertical, FutbolistaBase.ANGULO_VERTICAL_MAX ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, potencia, getMitad( anguloVertical, 0.0 ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, getMitadAlta( potencia, 1.0 ), getMitad( anguloVertical, 0.0 ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, getMitad( potencia, 0.5 ), getMitad( anguloVertical, 0.0 ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, getMitad( potencia, 0.5 ), anguloVertical );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
			
			golAlto = obtenerGolAlto( anguloBase, anguloError1, anguloError2, getMitad( potencia, 0.5 ), getMitadAlta( anguloVertical, FutbolistaBase.ANGULO_VERTICAL_MAX ) );
			if( golAlto.getEfectividadGol() == EfectividadGol.GOL ) {
				return golAlto.getBalon();
			}
			goles.add( golAlto );
		}
		
		
		return null;
	}
	
	
	private GolAlto obtenerGolAlto( double anguloBase, double anguloError1, double anguloError2, double potencia, double anguloVertical ) {
		double velocidadInicial = potencia * futbolista.getRemate();
		Balon balon = new Balon( futbolista.getPosicion(), anguloBase, velocidadInicial, anguloVertical );
		
		GolAlto golAlto = new GolAlto();
		golAlto.setBalon( balon );
		golAlto.setAnguloVertical( anguloVertical );
		golAlto.setPotencia( potencia );
		
		// exactitud gol
		PosicionCampo posicionRebote = balon.getPosicionRebote();
		PosicionBalon posicionEnLineaFondo = balon.getPosicionEnLineaFondo();
		double distanciaRebote = futbolista.getPosicion().distancia( posicionRebote );
		double distanciaDestino = futbolista.getPosicion().distancia( FutbolistaBase.POSICION_PORTERIA_RIVAL );
		if( posicionEnLineaFondo == null && distanciaRebote < distanciaDestino ) {
			golAlto.setExactitudGol( ExactitudGol.CORTO );
			golAlto.setDistanciaExactitud( distanciaDestino - distanciaRebote + Constantes.ALTO_ARCO ); // distanciaDestino - distanciaRebote + Constantes.ALTO_ARCO
		} else if( posicionEnLineaFondo != null && posicionEnLineaFondo.getAltura() < Constantes.ALTO_ARCO ) {
			golAlto.setExactitudGol( ExactitudGol.CORTO );
			golAlto.setDistanciaExactitud( Math.abs( posicionEnLineaFondo.getAltura() - Constantes.ALTO_ARCO ) );
		} else if( posicionEnLineaFondo != null && posicionEnLineaFondo.getAltura() > Constantes.ALTO_ARCO ) {
			golAlto.setExactitudGol( ExactitudGol.LARGO );
			golAlto.setDistanciaExactitud( Math.abs( posicionEnLineaFondo.getAltura() - Constantes.ALTO_ARCO ) );
		}
		
		// efectividad gol
		Balon balonGol = evaluarGol( anguloBase, anguloError1, anguloError2, potencia, anguloVertical );
		if( balonGol != null ) {
			golAlto.setEfectividadGol( EfectividadGol.GOL );
		} else {
			golAlto.setEfectividadGol( EfectividadGol.FUERA );
		}
		
		return golAlto;
	}
	
	
	private GolAlto buscarGolAlto( ArrayList<GolAlto> goles, ExactitudGol exactitud ) {
		GolAlto golAlto = null;
		for( int i = 0; i < goles.size(); i++ ) {
			if( golAlto == null && goles.get(i).getExactitudGol() == exactitud ) {
				golAlto = goles.get(i);
				
			} else if( golAlto != null && goles.get(i).getDistanciaExactitud() < golAlto.getDistanciaExactitud() ) {
				golAlto = goles.get(i);
			}
		}
		if( golAlto != null ) {
			goles.remove( golAlto );
		}
		return golAlto;
	}


}
